import { stringToClassName } from "../common/numToAutoFixed";
import { retrieveTopFill } from "../common/retrieveFill";
import { ComposeDefaultBuilder } from "./composeDefaultBuilder";
import { ComposeTextBuilder } from "./composeTextBuilder";
import { indentString } from "../common/indentString";

import {
  getCrossAxisAlignment,
  getMainAxisAlignment,
} from "./builderImpl/composeAutoLayout";
import { PluginSettings } from "types";
import { addWarning } from "../common/commonConversionWarnings";
import { getVisibleNodes } from "../common/nodeVisibility";

let localSettings: PluginSettings;
let previousExecutionCache: string[];

// Pre-compute static imports for performance
const COMPOSE_IMPORTS = `import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.*
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.graphics.BlendMode
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.*`;

const getFullScreenTemplate = (name: string, injectCode: string): string =>
  `${COMPOSE_IMPORTS}

// Generated by: https://www.figma.com/community/plugin/842128343887142055/
@Composable
fun ${name}Screen() {
    Surface(
        modifier = Modifier.fillMaxSize(),
        color = Color(0xFF1A2034)
    ) {
        ${name}()
    }
}

@Composable
fun ${name}() {
${indentString(injectCode, 4)}
}

@Preview(showBackground = true)
@Composable
fun ${name}Preview() {
    ${name}()
}`;

const getComposableTemplate = (name: string, injectCode: string): string =>
  `@Composable
fun ${name}() {
${indentString(injectCode, 4)}
}`;

export const composeMain = (
  sceneNode: ReadonlyArray<SceneNode>,
  settings: PluginSettings,
): string => {
  localSettings = settings;
  previousExecutionCache = [];

  // Handle empty input
  if (!sceneNode || sceneNode.length === 0) {
    return "// No nodes to convert";
  }

  let result = composeWidgetGenerator(sceneNode);

  // Handle empty result
  if (!result || result.trim() === "") {
    result = "// No visible content generated";
  }

  switch (localSettings.composeGenerationMode) {
    case "snippet":
      return result;
    case "composable":
      if (!result.startsWith("Column") && !result.startsWith("//")) {
        result = generateComposeWidget("Column", { content: [result] });
      }
      return getComposableTemplate(
        stringToClassName(sceneNode[0]?.name || "Component"),
        result,
      );
    case "screen":
      if (!result.startsWith("Column") && !result.startsWith("//")) {
        result = generateComposeWidget("Column", { content: [result] });
      }
      return getFullScreenTemplate(
        stringToClassName(sceneNode[0]?.name || "Component"),
        result,
      );
    default:
      return result;
  }
};

const generateComposeWidget = (
  widget: string,
  props: Record<string, any>,
): string => {
  const { content, ...modifiers } = props;

  let modifierChain = "";
  if (Object.keys(modifiers).length > 0) {
    modifierChain = `modifier = Modifier`;
    Object.entries(modifiers).forEach(([key, value]) => {
      if (value !== undefined && value !== null) {
        modifierChain += `.${key}(${value})`;
      }
    });
  }

  if (content && content.length > 0) {
    const contentStr = content.join(",\n");
    if (modifierChain) {
      return `${widget}(
    ${modifierChain}
) {
${indentString(contentStr, 4)}
}`;
    } else {
      return `${widget}() {
${indentString(contentStr, 4)}
}`;
    }
  } else {
    return modifierChain ? `${widget}(${modifierChain})` : `${widget}()`;
  }
};

const composeWidgetGenerator = (
  sceneNode: ReadonlyArray<SceneNode>,
): string => {
  let comp: string[] = [];

  const visibleSceneNode = getVisibleNodes(sceneNode);

  visibleSceneNode.forEach((node) => {
    switch (node.type) {
      case "RECTANGLE":
      case "ELLIPSE":
      case "STAR":
      case "POLYGON":
      case "LINE":
        comp.push(composeContainer(node, ""));
        break;
      case "GROUP":
        comp.push(composeGroup(node));
        break;
      case "FRAME":
      case "INSTANCE":
      case "COMPONENT":
      case "COMPONENT_SET":
        comp.push(composeFrame(node));
        break;
      case "SECTION":
        comp.push(composeContainer(node, ""));
        break;
      case "TEXT":
        comp.push(composeText(node));
        break;
      case "VECTOR":
        addWarning("VectorNodes are not fully supported in Compose");
        break;
      case "SLICE":
      default:
      // do nothing
    }
  });

  return comp.join(",\n");
};

const composeGroup = (node: GroupNode): string => {
  const widget = composeWidgetGenerator(node.children);
  return composeContainer(
    node,
    generateComposeWidget("Box", {
      content: widget ? [widget] : [],
    }),
  );
};

const composeContainer = (node: SceneNode, child: string): string => {
  let propChild = "";

  if ("fills" in node && node.fills !== figma.mixed && retrieveTopFill(node.fills as any)?.type === "IMAGE") {
    addWarning("Image fills are replaced with placeholders in Compose");
  }

  if (child.length > 0) {
    propChild = child;
  }

  const builder = new ComposeDefaultBuilder(propChild)
    .createContainer(node)
    .blendAttr(node)
    .position(node);

  return builder.child;
};

const composeText = (node: TextNode): string => {
  const builder = new ComposeTextBuilder().createText(node);
  previousExecutionCache.push(builder.child);

  return builder.blendAttr(node).textAutoSize(node).position(node).child;
};

const composeFrame = (
  node: SceneNode & BaseFrameMixin & MinimalBlendMixin,
): string => {
  const hasAbsoluteChildren = node.children.some(
    (child: any) => (child as any).layoutPositioning === "ABSOLUTE",
  );

  if (hasAbsoluteChildren && node.layoutMode !== "NONE") {
    addWarning(
      `Frame "${node.name}" has absolute positioned children. Using Box instead of ${
        node.layoutMode === "HORIZONTAL" ? "Row" : "Column"
      }.`,
    );
  }

  const children = composeWidgetGenerator(node.children);

  if (hasAbsoluteChildren) {
    return composeContainer(
      node,
      generateComposeWidget("Box", {
        content: children !== "" ? [children] : [],
      }),
    );
  }

  if (node.layoutMode !== "NONE") {
    const rowColumnWrap = makeRowColumnWrap(node, children);
    return composeContainer(node, rowColumnWrap);
  } else {
    if (node.inferredAutoLayout) {
      const rowColumnWrap = makeRowColumnWrap(
        node.inferredAutoLayout,
        children,
      );
      return composeContainer(node, rowColumnWrap);
    }

    if (node.isAsset) {
      return composeContainer(
        node,
        "Icon(Icons.Default.Home, contentDescription = null)",
      );
    }

    return composeContainer(
      node,
      generateComposeWidget("Box", {
        content: children !== "" ? [children] : [],
      }),
    );
  }
};

const makeRowColumnWrap = (
  autoLayout: InferredAutoLayoutResult,
  children: string,
): string => {
  const isRow = autoLayout.layoutMode === "HORIZONTAL";
  const composable = isRow ? "Row" : "Column";

  const widgetProps: Record<string, any> = {};

  // Add alignment properties
  if (isRow) {
    widgetProps.horizontalArrangement = getMainAxisAlignment(autoLayout);
    widgetProps.verticalAlignment = getCrossAxisAlignment(autoLayout);
  } else {
    widgetProps.verticalArrangement = getMainAxisAlignment(autoLayout);
    widgetProps.horizontalAlignment = getCrossAxisAlignment(autoLayout);
  }

  // Add spacing if needed
  if (autoLayout.itemSpacing > 0) {
    const arrangement = isRow ? "horizontalArrangement" : "verticalArrangement";
    const currentArrangement = widgetProps[arrangement];
    // If we already have an arrangement, combine with spacedBy
    if (currentArrangement && currentArrangement.includes("Arrangement.")) {
      widgetProps[arrangement] =
        `Arrangement.spacedBy(${autoLayout.itemSpacing}.dp, ${currentArrangement})`;
    } else {
      widgetProps[arrangement] =
        `Arrangement.spacedBy(${autoLayout.itemSpacing}.dp)`;
    }
  } else if (autoLayout.itemSpacing < 0) {
    addWarning("Compose doesn't support negative itemSpacing");
  }

  widgetProps.content = [children];

  return generateComposeWidget(composable, widgetProps);
};

export const composeCodeGenTextStyles = () => {
  const result = previousExecutionCache
    .map((style) => `${style}`)
    .join("\n// ---\n");

  if (!result) {
    return "// No text styles in this selection";
  }
  return result;
};
